<!DOCTYPE html><html lang="[&quot;zh-Hans&quot;,&quot;zh-CN&quot;,&quot;default&quot;]"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"><meta name="description" content="10天彻底搞定webpack4.0-笔记(1)"><meta name="keywords" content="webpack"><meta name="author" content="wenmu"><meta name="copyright" content="wenmu"><title>10天彻底搞定webpack4.0-笔记(1) | 温木的博客</title><link rel="shortcut icon" href="/melody-favicon.ico"><link rel="stylesheet" href="/css/index.css?version=1.6.1"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@latest/css/font-awesome.min.css?version=1.6.1"><link rel="dns-prefetch" href="https://cdn.staticfile.org"><link rel="dns-prefetch" href="https://cdn.bootcss.com"><link rel="dns-prefetch" href="https://creativecommons.org"><link rel="dns-prefetch" href="http://ta.qq.com"><script>(function() {
   var hm = document.createElement("script");
   hm.src = "https://tajs.qq.com/stats?sId=&lt;script type=&quot;text/javascript&quot; src=&quot;http://tajs.qq.com/stats?sId=66523541&quot; charset=&quot;UTF-8&quot;&gt;&lt;/script&gt;";
   var s = document.getElementsByTagName("script")[0];
   s.parentNode.insertBefore(hm, s);
 })();</script><script>var GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: undefined,
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  }
} </script><meta name="generator" content="Hexo 4.2.0"></head><body><i class="fa fa-arrow-right" id="toggle-sidebar" aria-hidden="true"></i><div id="sidebar"><div class="toggle-sidebar-info text-center"><span data-toggle="切换文章详情">切换站点概览</span><hr></div><div class="sidebar-toc"><div class="sidebar-toc__title">目录</div><div class="sidebar-toc__progress"><span class="progress-notice">你已经读了</span><span class="progress-num">0</span><span class="progress-percentage">%</span><div class="sidebar-toc__progress-bar"></div></div><div class="sidebar-toc__content"><ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#npm-script-命令给-webpack-传参"><span class="toc-number">1.</span> <span class="toc-text">npm script 命令给 webpack 传参</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#dev-server"><span class="toc-number">2.</span> <span class="toc-text">dev-server</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Html-webpack-plugin"><span class="toc-number">3.</span> <span class="toc-text">Html-webpack-plugin</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#loader"><span class="toc-number">4.</span> <span class="toc-text">loader</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#抽离-css"><span class="toc-number">5.</span> <span class="toc-text">抽离 css</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#css-自动加前缀"><span class="toc-number">6.</span> <span class="toc-text">css 自动加前缀</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#压缩-css"><span class="toc-number">7.</span> <span class="toc-text">压缩 css</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#转换-es6-语法"><span class="toc-number">8.</span> <span class="toc-text">转换 es6 语法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#js-规范"><span class="toc-number">9.</span> <span class="toc-text">js 规范</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#暴露第三方模块给全局"><span class="toc-number">10.</span> <span class="toc-text">暴露第三方模块给全局</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#不打包指定模块"><span class="toc-number">11.</span> <span class="toc-text">不打包指定模块</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#图片处理"><span class="toc-number">12.</span> <span class="toc-text">图片处理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#小图片的处理"><span class="toc-number">13.</span> <span class="toc-text">小图片的处理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#资源分类"><span class="toc-number">14.</span> <span class="toc-text">资源分类</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#多页面应用"><span class="toc-number">15.</span> <span class="toc-text">多页面应用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#代码映射"><span class="toc-number">16.</span> <span class="toc-text">代码映射</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#监控"><span class="toc-number">17.</span> <span class="toc-text">监控</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#小插件"><span class="toc-number">18.</span> <span class="toc-text">小插件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#跨域问题"><span class="toc-number">19.</span> <span class="toc-text">跨域问题</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#前端自己-mock-数据，不借助服务端"><span class="toc-number">20.</span> <span class="toc-text">前端自己 mock 数据，不借助服务端</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#服务端-node-启动-webpack"><span class="toc-number">21.</span> <span class="toc-text">服务端 node 启动 webpack</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#resolve"><span class="toc-number">22.</span> <span class="toc-text">resolve</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#环境变量"><span class="toc-number">23.</span> <span class="toc-text">环境变量</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#区分不同的环境"><span class="toc-number">24.</span> <span class="toc-text">区分不同的环境</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#webpack-优化"><span class="toc-number">25.</span> <span class="toc-text">webpack 优化</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#动态链接库"><span class="toc-number">26.</span> <span class="toc-text">动态链接库</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#多线程打包"><span class="toc-number">27.</span> <span class="toc-text">多线程打包</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#webpack-自带的优化功能"><span class="toc-number">28.</span> <span class="toc-text">webpack 自带的优化功能</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#抽取公共代码"><span class="toc-number">29.</span> <span class="toc-text">抽取公共代码</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#抽离第三方模块"><span class="toc-number">29.1.</span> <span class="toc-text">抽离第三方模块</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#懒加载"><span class="toc-number">30.</span> <span class="toc-text">懒加载</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#热更新"><span class="toc-number">31.</span> <span class="toc-text">热更新</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#tapable"><span class="toc-number">32.</span> <span class="toc-text">tapable</span></a></li></ol></div></div><div class="author-info hide"><div class="author-info__avatar text-center"><img src="https://i.loli.net/2020/02/27/xwaBoOj158MfNyq.jpg"></div><div class="author-info__name text-center">wenmu</div><div class="author-info__description text-center">记录一些在工作中或学习新知识时学到的一些知识点；正所谓好记性不如一个烂笔头，温故而知新！</div><hr><div class="author-info-articles"><a class="author-info-articles__archives article-meta" href="/archives"><span class="pull-left">文章</span><span class="pull-right">115</span></a><a class="author-info-articles__tags article-meta" href="/tags"><span class="pull-left">标签</span><span class="pull-right">52</span></a><a class="author-info-articles__categories article-meta" href="/categories"><span class="pull-left">分类</span><span class="pull-right">30</span></a></div></div></div><div id="content-outer"><div class="no-bg" id="top-container"><div id="page-header"><span class="pull-left"> <a id="site-name" href="/">温木的博客</a></span><i class="fa fa-bars toggle-menu pull-right" aria-hidden="true"></i><span class="pull-right menus"><a class="site-page" href="/">首页</a><a class="site-page" href="/archives">文章</a><a class="site-page" href="/tags">标签</a><a class="site-page" href="/categories">分类</a></span></div><div id="post-info"><div id="post-title">10天彻底搞定webpack4.0-笔记(1)</div><div id="post-meta"><time class="post-meta__date"><i class="fa fa-calendar" aria-hidden="true"></i> 2020-01-09</time><span class="post-meta__separator">|</span><i class="fa fa-inbox post-meta__icon" aria-hidden="true"></i><a class="post-meta__categories" href="/categories/webpack/">webpack</a></div></div></div><div class="layout" id="content-inner"><article id="post"><div class="article-container" id="post-content"><h3 id="npm-script-命令给-webpack-传参"><a href="#npm-script-命令给-webpack-传参" class="headerlink" title="npm script 命令给 webpack 传参"></a>npm script 命令给 webpack 传参</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run build -- --config webpack.config.js</span><br></pre></td></tr></table></figure>

<p>加上两个杠，表示后面是字符串，是参数。</p>
<h3 id="dev-server"><a href="#dev-server" class="headerlink" title="dev-server"></a>dev-server</h3><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">devServer:&#123;</span><br><span class="line">contentBase:'./build/' ,// 指定server启动的目录</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="Html-webpack-plugin"><a href="#Html-webpack-plugin" class="headerlink" title="Html-webpack-plugin"></a>Html-webpack-plugin</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> HtmlWebpackPlugin(&#123;</span><br><span class="line">  template:<span class="string">''</span>,</span><br><span class="line">  filename:<span class="string">''</span>,</span><br><span class="line">  hash:tue, <span class="comment">//在每个html后面加上hash</span></span><br><span class="line">  <span class="comment">//压缩html</span></span><br><span class="line">  minify:&#123;</span><br><span class="line">    removeAttributeQuotes:<span class="literal">true</span> <span class="comment">// 删除属性值上的双引号</span></span><br><span class="line">    collapseWhitespace:<span class="literal">true</span>,<span class="comment">// 压缩html成一行</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h3 id="loader"><a href="#loader" class="headerlink" title="loader"></a>loader</h3><p>css-loader 主要是解决<code>@import</code>、图片路径等这些语法</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  test: <span class="regexp">/\.css$/</span>;</span><br><span class="line">  use: [</span><br><span class="line">    &#123;</span><br><span class="line">      loader: <span class="string">"style-loader"</span>,</span><br><span class="line">      options: &#123;</span><br><span class="line">        insertAt: <span class="string">"top"</span>, <span class="comment">// 设置style标签插入的地方</span></span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  ];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="抽离-css"><a href="#抽离-css" class="headerlink" title="抽离 css"></a>抽离 css</h3><p>使用插件<code>mini-css-extract-plugin</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> MniCssExtractPlugin = riquire(<span class="string">"mini-css-extract-plugin"</span>);</span><br><span class="line"></span><br><span class="line">plugins: [</span><br><span class="line">  <span class="keyword">new</span> MiniCssExtractPlugin(&#123;</span><br><span class="line">    filename: <span class="string">"main.css"</span>,</span><br><span class="line">  &#125;),</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line"><span class="comment">//这是就不要放到style里面，所以style-loader就不要了</span></span><br><span class="line">&#123;</span><br><span class="line">  test: <span class="regexp">/\.css$/</span>;</span><br><span class="line">  use: [</span><br><span class="line">    <span class="comment">// css-loader执行后执行minicssextractplugin的loader</span></span><br><span class="line">    MiniCssExtractPlugin.loader,</span><br><span class="line">    <span class="string">"css-loader"</span>,</span><br><span class="line">  ];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="css-自动加前缀"><a href="#css-自动加前缀" class="headerlink" title="css 自动加前缀"></a>css 自动加前缀</h3><p>使用 autoprefixer 插件，但是需要 postcss-loader 对它进行解析。<br>在 css-loader 之前 less-loader 使用 postcss-loader</p>
<h3 id="压缩-css"><a href="#压缩-css" class="headerlink" title="压缩 css"></a>压缩 css</h3><p>默认情况下，webpack 使用<code>uglifyjs-webpack-plugin</code>插件在生产环境打包时已经压缩了 js，但如果使用了<code>mini-css-extract-plugin</code>，则需要自己单独再配置压缩优化相关项，<a href="[https://www.npmjs.com/package/mini-css-extract-plugin](https://www.npmjs.com/package/mini-css-extract-plugin)">可查看官网</a>。<br>压缩 js 可以使用<code>uglifyjs-webpack-plugin</code>，也可以使用下面的。压缩 css 需要插件<code>optimize-css-assets-webpack-plugin</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> TerserJSPlugin = <span class="built_in">require</span>(<span class="string">'terser-webpack-plugin'</span>);</span><br><span class="line"><span class="keyword">const</span> MiniCssExtractPlugin = <span class="built_in">require</span>(<span class="string">'mini-css-extract-plugin'</span>);</span><br><span class="line"><span class="keyword">const</span> OptimizeCSSAssetsPlugin = <span class="built_in">require</span>(<span class="string">'optimize-css-assets-webpack-plugin'</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  optimization: &#123;<span class="comment">// 优化项</span></span><br><span class="line">    minimizer: [<span class="keyword">new</span> TerserJSPlugin(&#123;&#125;), <span class="keyword">new</span> OptimizeCSSAssetsPlugin(&#123;&#125;)],</span><br><span class="line">  &#125;,</span><br><span class="line">....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="转换-es6-语法"><a href="#转换-es6-语法" class="headerlink" title="转换 es6 语法"></a>转换 es6 语法</h3><p>babel-loader<br>babel-core<br>babel/preset-env</p>
<p>@babel/plugin-transform-runtime 和 @babel/runtime 解决更高级语法 api 没有的问题，比如 generator</p>
<h3 id="js-规范"><a href="#js-规范" class="headerlink" title="js 规范"></a>js 规范</h3><p>使用 eslint-loader 和 eslint<br>如果只是使用 eslint，帮助在开发过程中进行检测，会提示文件中语法不符合规则的部分。但是在打包的时候不会做校验。使用 eslint-loader,在 webpack 进行打包的时候进行校验。<br>eslint-loader 通常单独配置，不建议和 bable 等其他处理 js 的 loader 写在一块。可以通过<code>enforce</code>设置执行顺序，</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"> &#123;</span><br><span class="line">    enforce: <span class="string">"pre"</span>,<span class="comment">//在其他loader之前执行，使用post在其他loader之后执行</span></span><br><span class="line">    test: <span class="regexp">/\.js$/</span>,</span><br><span class="line">    exclude: <span class="regexp">/node_modules/</span>,</span><br><span class="line">    loader: <span class="string">"eslint-loader"</span></span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<h3 id="暴露第三方模块给全局"><a href="#暴露第三方模块给全局" class="headerlink" title="暴露第三方模块给全局"></a>暴露第三方模块给全局</h3><p>比如我们安装了 jquery，我们可以在每个模块中 import 进来，然后使用，这样是没问题的，但是如果想通过 window 访问这些包，就不行了，可以通过下面的方法来实现。</p>
<blockquote>
<p>下面简单说下 loader 的分类：</p>
<ul>
<li>pre 前置 loader,前面执行的 loader</li>
<li>normal 普通的 loader</li>
<li>内联 loader</li>
<li>post 后置 loader</li>
</ul>
</blockquote>
<p>比如使用<code>expose-loader</code>。</p>
<ol>
<li>通过内联 loader 的方式来实现把 jquery 暴露给 window。</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> $ <span class="keyword">from</span> <span class="string">"expose-loader?$!jquery"</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="built_in">window</span>.$); <span class="comment">// window上存在$</span></span><br></pre></td></tr></table></figure>

<p>但是上面的写法不美观，可以在配置文件中配置。</p>
<ol start="2">
<li>在配置文件中配置</li>
</ol>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    test:require.resolve('jquery'),</span><br><span class="line">    use:'expose-loader?$'</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//使用</span></span><br><span class="line">import $ from 'jquery'</span><br><span class="line">console.log(window.$)</span><br></pre></td></tr></table></figure>

<p>不用引用直接使用呢？</p>
<ol start="3">
<li>在每个模块中注入$对象<br>通过<code>webpack</code>的<code>ProviderPlugin</code>插件</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> webpack = <span class="built_in">require</span>(<span class="string">"webpack"</span>);</span><br><span class="line"></span><br><span class="line">plugins: [</span><br><span class="line">  <span class="comment">// 在每个模块中都注入</span></span><br><span class="line">  <span class="keyword">new</span> webpack.ProviderPlugin(&#123;</span><br><span class="line">    $: <span class="string">"jquery"</span>,</span><br><span class="line">  &#125;),</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line"><span class="comment">//因为是注入到每个模块中的，所以在每个模块中可以直接使用，但window.$不存在</span></span><br><span class="line"><span class="built_in">console</span>.log($);</span><br></pre></td></tr></table></figure>

<h3 id="不打包指定模块"><a href="#不打包指定模块" class="headerlink" title="不打包指定模块"></a>不打包指定模块</h3><p>比如在<code>index.html</code>中手动引入了<code>jquery</code>包，那就不需要对<code>jquery</code>进行打包。通过设置<code>webpack</code>的<code>externals</code>属性可以实现该功能。</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">externals:&#123;</span><br><span class="line">    jquery:"$"</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>即使在代码中使用 import 的方式引入，也不会进行打包。</p>
<h3 id="图片处理"><a href="#图片处理" class="headerlink" title="图片处理"></a>图片处理</h3><p>file-loader 默认会在内部生成一张图片到输出目录下，把生成的图片的名字返回回来。 ### 在 html 中使用 img<br>因为 webpack 会对模块中引用的 img 进行打包转换等处理，所以如果直接在 index.html 中使用 img 是识别不了的。如下</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">"./logo.png"</span> /&gt;</span></span><br></pre></td></tr></table></figure>

<p>因为打包后原来的 logo.png 的名字和路径都发生了变化，所以这种写法是肯定拿不到的。<br>使用<code>html-withimg-loader</code>可以解决这个问题。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  test: <span class="regexp">/\.html/</span>;</span><br><span class="line">  use: <span class="string">"html-withimg-loader"</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="小图片的处理"><a href="#小图片的处理" class="headerlink" title="小图片的处理"></a>小图片的处理</h3><p>使用<code>url-loader</code>可以使用 base64 的方式减少对图片的请求。</p>
<h3 id="资源分类"><a href="#资源分类" class="headerlink" title="资源分类"></a>资源分类</h3><ol>
<li>图片</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    test:<span class="regexp">/\.(jpg|png|jpeg|svg)/</span></span><br><span class="line">    use:&#123;</span><br><span class="line">        lader:<span class="string">'url-loader'</span>,</span><br><span class="line">        options:&#123;</span><br><span class="line">            limit:<span class="number">2</span>*<span class="number">1024</span>,</span><br><span class="line">            outputPath:<span class="string">'img/'</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>css</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> MiniCssExdtractPlugin(&#123;</span><br><span class="line">  filename: <span class="string">"css/main.css"</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>就是在各个资源前面加上文件夹名即可</p>
<blockquote>
<p>如果需要在每个资源前面统一加上一个前缀，比如 cdn，可以配置 webpack 输出路径的 publicpath</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line"> output:&#123;</span><br><span class="line">   filename:<span class="string">'bundle.js'</span>.</span><br><span class="line">   path:path.resolve(__dirname,<span class="string">'build'</span>),</span><br><span class="line">   publicPath:<span class="string">'https://www.baiducdn.com/'</span></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果需要在不同的资源前面家不同的 cdn，可以在各自 loader 上加上 publicPath</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">   test:<span class="regexp">/\.(jpg|png|jpeg|svg)/</span></span><br><span class="line">   use:&#123;</span><br><span class="line">       lader:<span class="string">'url-loader'</span>,</span><br><span class="line">       options:&#123;</span><br><span class="line">           limit:<span class="number">2</span>*<span class="number">1024</span>,</span><br><span class="line">           outputPath:<span class="string">'img/'</span>,</span><br><span class="line">           publicPath:<span class="string">'https://www.baidu.com/'</span></span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</blockquote>
<h3 id="多页面应用"><a href="#多页面应用" class="headerlink" title="多页面应用"></a>多页面应用</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">"path"</span>);</span><br><span class="line"><span class="keyword">const</span> HtmlWebpackPlugin = <span class="built_in">require</span>(<span class="string">"html-webpack-plugin"</span>);</span><br><span class="line"><span class="keyword">const</span> webpack = <span class="built_in">require</span>(<span class="string">"webpack"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> config = &#123;</span><br><span class="line">  mode: <span class="string">"development"</span>,</span><br><span class="line">  entry:&#123;</span><br><span class="line">        home:<span class="string">'./src/home.js'</span>,</span><br><span class="line">        other:<span class="string">'./src/other.js'</span></span><br><span class="line">  &#125;,</span><br><span class="line">  output: &#123;</span><br><span class="line">    path: path.join(__dirname, <span class="string">"dist/"</span>),</span><br><span class="line">    <span class="comment">//输出时只要根据每个入口的名字输出就行</span></span><br><span class="line">    filename: <span class="string">"js/[name].js"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">plugins:[</span><br><span class="line">    <span class="comment">// 模板输出html文件无法使用入口定义的名字，</span></span><br><span class="line">    <span class="comment">//只能使用多个模板实例来解决多个的问题。</span></span><br><span class="line">    <span class="comment">//但需要使用chunk来指定加载打包的js</span></span><br><span class="line">    <span class="keyword">new</span> HtmlWebpackPlugin(&#123;</span><br><span class="line">          template:<span class="string">'./home.html'</span>,</span><br><span class="line">          filename:<span class="string">'home.html'</span>,</span><br><span class="line">          chunks:[<span class="string">'home'</span>]</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">new</span> HtmlWebpackPlugin(&#123;</span><br><span class="line">          template:<span class="string">'./home.html'</span>,</span><br><span class="line">          filename:<span class="string">'home.html'</span>,</span><br><span class="line">          chunks:[<span class="string">'home'</span>]</span><br><span class="line">    &#125;);</span><br><span class="line">]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="代码映射"><a href="#代码映射" class="headerlink" title="代码映射"></a>代码映射</h3><p>配置了 sourcemap 不仅仅是开发的时候有映射，生产环境也会有(当然生产环境不配置就没有了)。</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"devtool"</span>: <span class="string">"source-map"</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>source-map<br>源码映射，会单独生成一个 source map 文件，出错了会列出报错的列和行号。</li>
<li>eval-sorce-map<br>不会产生单独的文件，但是可以显示出错的行和列;并且在浏览器中也能看到源码。eval 标明，这种方式是使用 eval 的方式把源码生成字符串，集成在打包后的文件中，然后 eval 出来。</li>
<li>cheap-module-source-map<br>不显示出错的行和列，但是生成一个单独的文件，并且和调试<strong>没有</strong>关联起来。</li>
<li>cheap-module-eval-source-map<br>不生成文件，集成在打包后的文件中， 也不会产生列</li>
</ul>
<h3 id="监控"><a href="#监控" class="headerlink" title="监控"></a>监控</h3><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"watch"</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="attr">"watchOptions"</span>: &#123;</span><br><span class="line">    <span class="attr">"poll"</span>: <span class="number">100</span>, <span class="comment">// 每秒检测的次数</span></span><br><span class="line">    <span class="attr">"aggregateTimeout"</span>: <span class="number">500</span>, <span class="comment">// 防抖，500毫秒内的变化</span></span><br><span class="line">    <span class="attr">"ignored"</span>: <span class="string">"/node_modules/"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="小插件"><a href="#小插件" class="headerlink" title="小插件"></a>小插件</h3><ul>
<li>cleanWebpackPlugin<br>每次打包，先清空指定目录中的旧文件。</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> cleanWebpackPlugin(<span class="string">"./dist"</span>);</span><br></pre></td></tr></table></figure>

<ul>
<li>copyWebpackPlugin<br>打包的时候，有些静态资源可能不会被打包，但也是需要放到打包目录中，使用这个插件，就可以实现该功能。</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> copyWebpackPlugin([&#123; <span class="attr">from</span>: <span class="string">"doc"</span>, <span class="attr">to</span>: <span class="string">"/"</span> &#125;]);</span><br></pre></td></tr></table></figure>

<ul>
<li>bannerPlugin(内置的 )<br>给打包后的代码加上版权信息。</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> webpack.BannerPlugin(<span class="string">"make by wenmu 2019 "</span>);</span><br></pre></td></tr></table></figure>

<h3 id="跨域问题"><a href="#跨域问题" class="headerlink" title="跨域问题"></a>跨域问题</h3><p>就是设置<code>devServer</code>的<code>proxy</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">devServer:&#123;</span><br><span class="line">    proxy:&#123;</span><br><span class="line">        <span class="string">'/api'</span>:<span class="string">"http://localhost:4567"</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面就把以<code>/api</code>开头的请求链接都转到<code>http://localhost:4567</code>的服务上。比如<code>/api/user/getDetail</code>,发出的请求就是<code>http://localhost:4567/api/user/getDetail</code>。<br><strong>如果服务端的链接不带<code>/api</code>怎么办？</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">devServer: &#123;</span><br><span class="line">  proxy: &#123;</span><br><span class="line">    <span class="string">'/api'</span>: &#123;</span><br><span class="line">      target: <span class="string">'http://localhost:3000'</span>,</span><br><span class="line">      pathRewrite: &#123;<span class="string">'^/api'</span> : <span class="string">''</span>&#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="前端自己-mock-数据，不借助服务端"><a href="#前端自己-mock-数据，不借助服务端" class="headerlink" title="前端自己 mock 数据，不借助服务端"></a>前端自己 mock 数据，不借助服务端</h3><p>我们知道，其实 devServer 本身就是一个 node 服务。我们可以使用这个服务直接处理请求。这需要借助 devServer 的 before 钩子函数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">devServer: &#123;</span><br><span class="line">   before: <span class="function"><span class="keyword">function</span>(<span class="params">app, server</span>) </span>&#123;</span><br><span class="line">     app.get(<span class="string">'/some/path'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">req, res</span>) </span>&#123;</span><br><span class="line">       res.json(&#123; <span class="attr">custom</span>: <span class="string">'response'</span> &#125;);</span><br><span class="line">     &#125;);</span><br><span class="line">   &#125;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<p><code>app</code>就是<code>devServer</code>中的<code>express</code>实例。<br>如果一个一个的请求都写到这里面，这个文件会比较大，所以可以把相关的请求函数封装到一起，在这里调用即可。通常使用第三方封装的组件<code>mocker-api</code>帮助 mock 数据。<code>mocker-api</code>就是这个原理。</p>
<h3 id="服务端-node-启动-webpack"><a href="#服务端-node-启动-webpack" class="headerlink" title="服务端 node 启动 webpack"></a>服务端 node 启动 webpack</h3><p>使用<code>node</code>启动<code>webpack</code>，这样在<code>node</code>中写的<code>mock</code>数据就和<code>webpack</code>启动的前端是一个端口，就不存在跨域问题了。<br>在服务端中启动<code>webpack</code>，需要使用<code>webpack</code>的中间件<code>webpack-dev-middleware</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">"express"</span>);</span><br><span class="line"><span class="keyword">const</span> webpack = <span class="built_in">require</span>(<span class="string">"webpack"</span>);</span><br><span class="line"><span class="keyword">const</span> middleware = <span class="built_in">require</span>(<span class="string">"webpack-dev-middleware"</span>);</span><br><span class="line"><span class="keyword">const</span> config = <span class="built_in">require</span>(<span class="string">"./webpack.config.js"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> compiler = webpack(config);</span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> express();</span><br><span class="line">app.use(middleware(compiler));</span><br><span class="line"></span><br><span class="line">app.get(<span class="string">"/user"</span>, (req, res) =&gt; &#123;</span><br><span class="line">  res.json(&#123; <span class="attr">name</span>: <span class="string">"test data."</span> &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.listen(<span class="number">3000</span>);</span><br></pre></td></tr></table></figure>

<h3 id="resolve"><a href="#resolve" class="headerlink" title="resolve"></a>resolve</h3><p>resolve 的作用就是解析，项目中的各种解析都可以在这里做相关的配置。</p>
<ul>
<li>第三方包的查找<br>默认情况下，当引入一个包时，首先在<code>node_modules</code>中查找，如果找不到就再去全局包安装目录查找，再找不到就报错了。我们可以通过配置 <code>modules</code>来强制指定只在哪些目录中进行查找，比如只在<code>node_modules</code>中</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">resolve:&#123;</span><br><span class="line">    modules:[path.resolve(<span class="string">'node_modules'</span>)]</span><br><span class="line">&#125;,</span><br><span class="line">devServer:&#123;&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>别名<br>如果一个路径的比较长，引用起来比较麻烦，可以通过在 resolve 中对路径设置别名来解决。<br>比如应用 bootstrap 的样式，<code>bootstrap/dist/css/bootstrap.css</code></li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">resolve: &#123;</span><br><span class="line">  alias: &#123;</span><br><span class="line">    BootstrapStyle: <span class="string">"bootstrap/dist/css/bootstrap.css"</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这是可以直接引用<code>BootstrapStyle</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> BootstrapStyle;</span><br></pre></td></tr></table></figure>

<ul>
<li>优先读取的 package 字段<br>在引用一个包时，默认是读取包中<code>package.json</code>中<code>main</code>字段配置的文件，如下是<code>bootstrap</code>的<code>package.json</code>，当<code>import bootstrap</code>时，读取的是 js 文件。</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">style:<span class="string">'/dist/css/bootstrap.css'</span>,</span><br><span class="line">main:<span class="string">'/dist/js/bootstrap.js'</span></span><br></pre></td></tr></table></figure>

<p>我们可以设置引入包时，优先读取的字段，比如优先读取<code>style</code>字段，找不到了再读取<code>main</code>字段对应的文件。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">resolve: &#123;</span><br><span class="line">   mainFields: [<span class="string">'style'</span>, <span class="string">'main'</span>],</span><br><span class="line">   mainFiles:[<span class="string">'index'</span>] <span class="comment">// 入口文件的名字</span></span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<p>这样当<code>import bootstrap</code>时，bootstrap 的样式就被加载了。</p>
<ul>
<li>默认扩展名<br>在引入一些文件时，比如 js，后缀名是不需要写的，但是 css 的后缀是必须写的，我们是可以设置一些类型不需要些扩展名的</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">resolve: &#123;</span><br><span class="line">  extensions: [<span class="string">".js"</span>, <span class="string">".css"</span>, <span class="string">".jsx"</span>, <span class="string">".json"</span>];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>引入一个文件时，会先找 js，找不到再找 css，依次 jsx、json 等等。当匹配到一个时，就不会继续再匹配了。因此存在多种类型的文件使用一个文件名时，当引入这个文件名时，只会加载设置的第一个类型。如果引用 css，还是需要加上后缀。</p>
<h3 id="环境变量"><a href="#环境变量" class="headerlink" title="环境变量"></a>环境变量</h3><p>webpack 提供了一个插件可以帮助我们定义一些环境变量;<code>webpack.DefinePlugin</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> webpack.DefinePlugin(&#123;</span><br><span class="line">  NAME: <span class="string">"'wenmu'"</span>,</span><br><span class="line">  DEV: <span class="built_in">JSON</span>.stringify(process.env.NODE_ENV),</span><br><span class="line">  Express: <span class="string">"1+1"</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>这样上面定义的变量就可以直接使用了。<br>细心的同学发现，为什么<code>NAME</code>的值要用双引号把包括单引号呢？<br>因为在读取变量时，会把后面单引号中的直接复制给变量，那读取上面的<code>NAME</code>就成了<code>wenmu</code>,而不是<code>&#39;wenmu&#39;</code>那就会报错，说 wenmu 未定义了，当成一个变量了。比如 Express 就是 2，不是<code>1+1</code>字符串。<br>可以使用双引号再包裹一下，但推荐使用第二种的写法，可读性强。</p>
<h3 id="区分不同的环境"><a href="#区分不同的环境" class="headerlink" title="区分不同的环境"></a>区分不同的环境</h3><p>通常开发和生产使用的 webapck 配置文件是不一样的，但是大部分的配置是一样的，因此写一个 base 文件，再写两个开发和生产的“继承”base 即可。继承就用到了<code>webpack-merge</code>.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> &#123; smart &#125; = <span class="built_in">require</span>(<span class="string">"webapck-merge"</span>);</span><br><span class="line"><span class="keyword">const</span> base = <span class="built_in">require</span>(<span class="string">"./webapck.base.js"</span>);</span><br><span class="line"></span><br><span class="line">modules.export = smart(base, &#123;</span><br><span class="line">  mode: <span class="string">"production"</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="webpack-优化"><a href="#webpack-优化" class="headerlink" title="webpack 优化"></a>webpack 优化</h3><ol>
<li>noParse<br>noParse 指定不需要解析的包，当一个包比较大，并且没有依赖其他包时，可以使用 noParse 指定，这样可以减少打包时间。</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="comment">//...</span></span><br><span class="line">  <span class="built_in">module</span>: &#123;</span><br><span class="line">    noParse: <span class="regexp">/jquery|lodash/</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>设置 loader 解析的范围</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>: &#123;</span><br><span class="line">  rules: [</span><br><span class="line">    &#123;</span><br><span class="line">      test: <span class="regexp">/\.js$/</span>,</span><br><span class="line">      exclude: <span class="regexp">/node_modules/</span>, <span class="comment">//排除不需要解析的</span></span><br><span class="line">      include: path.resolve(<span class="string">"src"</span>), <span class="comment">// 设置需要解析的</span></span><br><span class="line">      use: &#123;</span><br><span class="line">        loader: [<span class="string">"babel-loader"</span>],</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  ];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol start="3">
<li>ignorePlugin<br>在使用一个写第三方包时，包可能会引入很多文件，但是一些文件可能对我们的项目是没用的。<br>比如有一个 moment，这个包做了国际化处理，默认它会把所有的语言包都加载，如果我们只使用了中文，这样打包的时候就比较大，这时可以使用 webpack 提供的 IgnorePlugin 来指定这个包哪些文件不需要加载。</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">plugins: [<span class="keyword">new</span> webpack.IgnorePlugin(<span class="regexp">/\.\/locale/</span>, /moment/)];</span><br></pre></td></tr></table></figure>

<p>这时国际化就不管用了，中文的语言包需要手动引入。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">"moment/locale/zh-cn"</span>;</span><br><span class="line"></span><br><span class="line">moment.locale(<span class="string">"zh-cn"</span>);</span><br></pre></td></tr></table></figure>

<h3 id="动态链接库"><a href="#动态链接库" class="headerlink" title="动态链接库"></a>动态链接库</h3><p>默认在打包时，所有的包都会被到包在一起，包括第三方库，这样每次打包的时候，第三方库和有些公共的文件也需要每次都重新进行打包，这样不仅打出的包比较大，并且打包会比较慢。<br>因此我们可以把第三方库和一些公共的文件抽离出来，先单独进行打包。比如 react、react-dom 等等。然后开发的时候引用我们单独打好的包，这样每次打包的时候，单独抽离出来的包就不会再次进行打包了。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/******/</span> <span class="keyword">var</span> abc= (<span class="function"><span class="keyword">function</span>(<span class="params">modules</span>) </span>&#123; <span class="comment">// webpackBootstrap</span></span><br><span class="line"><span class="comment">/******/</span> 	<span class="comment">// The module cache</span></span><br><span class="line"><span class="comment">/******/</span> 	<span class="keyword">var</span> installedModules = &#123;&#125;;</span><br><span class="line"><span class="comment">/******/</span></span><br><span class="line"><span class="comment">/******/</span> 	<span class="comment">// The require function</span></span><br><span class="line"><span class="comment">/******/</span> 	<span class="function"><span class="keyword">function</span> <span class="title">__webpack_require__</span>(<span class="params">moduleId</span>) </span>&#123;</span><br><span class="line">                ....</span><br><span class="line"><span class="comment">/******/</span> 		<span class="keyword">return</span> <span class="built_in">module</span>.exports;</span><br><span class="line"><span class="comment">/******/</span> 	&#125;</span><br><span class="line"><span class="comment">/******/</span>        ....</span><br><span class="line"><span class="comment">/******/</span> 	<span class="comment">// Load entry module and return exports</span></span><br><span class="line"><span class="comment">/******/</span> 	<span class="keyword">return</span> __webpack_require__(__webpack_require__.s = <span class="string">"./src/aaa.js"</span>);</span><br><span class="line"><span class="comment">/******/</span> &#125;)</span><br><span class="line"><span class="comment">/******/</span> (&#123;</span><br><span class="line"><span class="comment">/***/</span> <span class="string">"./src/aaa.js"</span>:</span><br><span class="line">  !*** ./src/aaa.js ***!</span><br><span class="line"><span class="comment">/*! no static exports found */</span></span><br><span class="line"><span class="comment">/***/</span> (<span class="function"><span class="keyword">function</span>(<span class="params">module, exports</span>) </span>&#123;</span><br><span class="line"><span class="built_in">eval</span>(<span class="string">"module.exports = \"this is a value\";\n\n\n//# sourceURL=webpack:///./src/aaa.js?"</span>);</span><br><span class="line"><span class="comment">/***/</span> &#125;)</span><br><span class="line"><span class="comment">/******/</span> &#125;);</span><br></pre></td></tr></table></figure>

<p>上面是打包后的代码结构，大部分删除了。<code>var abc=</code>是手动写上的。</p>
<blockquote>
<p>简单讲解下打包后文件的代码结构。<br> 一个模块打包后，原来的模块会被封装成一个立即执行 function，js 中其实类或模块都是 function 的语法糖吗，这个 function 会把打包的模块做一个对象返回。我们在引用模块的时候，其实就是接受这个 function 的返回值。<br> 我们把这个函数的返回值赋给一个变量，然后</p>
</blockquote>
<p>基于上面的讲解，我们可以在配置文件中指定，接收打包后返回值的变量名。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">"path"</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  mode: <span class="string">"development"</span>,</span><br><span class="line">  entry: &#123;</span><br><span class="line">    test: <span class="string">"./src/aaa.js"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  output: &#123;</span><br><span class="line">    filename: <span class="string">"[name].js"</span>,</span><br><span class="line">    path: path.resolve(__dirname, <span class="string">"dist"</span>),</span><br><span class="line">    library: <span class="string">"abc"</span>, <span class="comment">// 接收的变量名</span></span><br><span class="line">    <span class="comment">// 指定接收的方式，可以是变量的方式var(默认 )，也可以是commonjs，amd等其他方式。</span></span><br><span class="line">    libraryTarget: <span class="string">"var"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>加上<code>library</code>的配置后，上面的手动写的<code>var abc=1</code>就不用手动写了，打包出来的就是这样的。</p>
<p>动态链接库就是基于上面的原理来做的，只是我们需要打包的是 react、react-dom 等包。</p>
<ol>
<li>如何让 webpack 知道上面生成的文件就是动态链接库呢？<br>这就需要用到<code>webpack</code>的自带插件<code>DllPlugin</code>,它能指定把哪个文件打包成动态链接库，并且用一个清单(<code>manifest.json</code>)的方式进行管理。<code>manifest.json</code>记录了如何查找动态链接库中的文件。</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">"path"</span>);</span><br><span class="line"><span class="keyword">const</span> webpack = <span class="built_in">require</span>(<span class="string">"webpack"</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  mode: <span class="string">"development"</span>,</span><br><span class="line">  entry: &#123;</span><br><span class="line">    react: [<span class="string">"react"</span>, <span class="string">"react-dom"</span>],</span><br><span class="line">  &#125;,</span><br><span class="line">  output: &#123;</span><br><span class="line">    filename: <span class="string">"_dll_[name].js"</span>,</span><br><span class="line">    path: path.resolve(__dirname, <span class="string">"dist"</span>),</span><br><span class="line">    library: <span class="string">"_dll_[name]"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [</span><br><span class="line">    <span class="keyword">new</span> webpack.DllPlugin(&#123;</span><br><span class="line">      <span class="comment">// name==library</span></span><br><span class="line">      name: <span class="string">"_dll_[name]"</span>,</span><br><span class="line">      path: path.resolve(__dirname, <span class="string">"dist"</span>, <span class="string">"manifest.json"</span>),</span><br><span class="line">    &#125;),</span><br><span class="line">  ],</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>使用 webpack 编译后，会生成一个<code>_dll_react.js</code>和<code>manifest.json</code>两个文件。</p>
<ul>
<li><code>_dll_react.js</code>中就是打包后的<code>react</code>和<code>react-dom</code></li>
<li><code>manifest.json</code>，记录了<code>_dll_react</code>中的依赖关系。这个主要是被<code>DllReferencePlugin</code>使用。</li>
</ul>
<p>打包完以后，就需要在入口 index.html 文件中引用。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"/_dll_react.js "</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>虽然引用了，但是打包的时候，react、react-dom 默认还是去<code>node_modules</code>中找，找到了然后就又被打包了，那怎么办，上面的工作不是白做了吗，这就需要用到<code>webpack</code>的另一个插件<code>DllReferencePlugin</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> webpack.DllReferencePlugin(&#123;</span><br><span class="line">  manifest: path.resolve(__dirname, <span class="string">"dist"</span>, <span class="string">"manifest.json"</span>),</span><br><span class="line">&#125;),</span><br></pre></td></tr></table></figure>

<blockquote>
<p>注意：这个和<code>DllPlugin</code>不在一个配置文件中，这个是开发打包使用的<code>webpack配置文件</code>,而<code>DllPlugin</code>是专门用来提取的公共包的<code>webpack配置</code>文件。</p>
</blockquote>
<p>这样配置后，打包的时候会先去清单中查找包，找不到了再把包打包进当前的代码中。这样打包出来的文件往往很小，因为公用包都已经在<code>_dll_react.js</code>中了</p>
<h3 id="多线程打包"><a href="#多线程打包" class="headerlink" title="多线程打包"></a>多线程打包</h3><p>多现成打包主要用到了<code>happypack</code>插件。这个很简单，主要就是把原来的 loader 换成 happypack 的 loader，然后在 plugin 中配置 happypack 即可。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">exports.plugins = [</span><br><span class="line">  <span class="keyword">new</span> HappyPack(&#123;</span><br><span class="line">    id: <span class="string">"jsx"</span>,</span><br><span class="line">    threads: <span class="number">4</span>,</span><br><span class="line">    loaders: [<span class="string">"babel-loader"</span>],</span><br><span class="line">  &#125;),</span><br><span class="line"></span><br><span class="line">  <span class="keyword">new</span> HappyPack(&#123;</span><br><span class="line">    id: <span class="string">"styles"</span>,</span><br><span class="line">    threads: <span class="number">2</span>,</span><br><span class="line">    loaders: [<span class="string">"style-loader"</span>, <span class="string">"css-loader"</span>, <span class="string">"less-loader"</span>],</span><br><span class="line">  &#125;),</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line">exports.module.rules = [</span><br><span class="line">  &#123;</span><br><span class="line">    test: <span class="regexp">/\.js$/</span>,</span><br><span class="line">    use: <span class="string">"happypack/loader?id=jsx"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  &#123;</span><br><span class="line">    test: <span class="regexp">/\.less$/</span>,</span><br><span class="line">    use: <span class="string">"happypack/loader?id=styles"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">];</span><br></pre></td></tr></table></figure>

<p>非常 easy.</p>
<h3 id="webpack-自带的优化功能"><a href="#webpack-自带的优化功能" class="headerlink" title="webpack 自带的优化功能"></a>webpack 自带的优化功能</h3><ol>
<li>tree-shaking<br>当我们使用 import 的方式引用一个模块时，如果只是引用了模块的部分方法，那在生产环境打包的时候，那些没有引用的方法会被删除掉。不会被打包进来。<br>但当使用 require 的方式引用模块时不会删除没用到的代码。<br>这是由<code>require</code>和<code>import</code>的机制相关的。</li>
<li>scope hosting 作用域提升</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">let</span> b = <span class="number">2</span>;</span><br><span class="line"><span class="keyword">let</span> c = <span class="number">3</span>;</span><br><span class="line"><span class="built_in">console</span>.log(a + b + c);</span><br></pre></td></tr></table></figure>

<p>上面的代码打包的时候，不会把 a、b、c 都打包进来，打包进来的是一个结果，<code>console.log(6)</code>,类似的模块引用等都会做类似的处理。</p>
<h3 id="抽取公共代码"><a href="#抽取公共代码" class="headerlink" title="抽取公共代码"></a>抽取公共代码</h3><p>抽取公共代码，是当有多个页面的时候(不都是单页面应用 )，多个个页面之间有公共的模块引用，打包的时候，默认会把公用的包在每个引用的页面中都打一份，造成公共代码的重复；<br>比如现在有多个入口</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">entry: &#123;</span><br><span class="line">  index: './src/index.js',</span><br><span class="line">  other:'./src/other.js',</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<p>当 index.js 和 other.js 中引用的有相同的模块时，可以把这些公用的模块抽离出来，这样打包的时候每个页面只有对公共模块的引用，不会在每个包中都包含一份，并且在访问 index 的时候就会被缓存，再访问 other 的时候，就不需要再下载了，从而提高性能。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  optimization: &#123;</span><br><span class="line">    splitChunks: &#123;</span><br><span class="line">      <span class="comment">// 分割代码块</span></span><br><span class="line">      cacheGroups: &#123;</span><br><span class="line">        <span class="comment">// 缓存组</span></span><br><span class="line">        common: &#123;</span><br><span class="line">          minChunks: <span class="number">2</span>,</span><br><span class="line">          chunks: <span class="string">"initial"</span>, <span class="comment">//只优化同步加载的模块</span></span><br><span class="line">          reuseExistingChunk: <span class="literal">true</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>上面是一个很简单的配置，可以去官网查看比较全面的配置，这里需要讲解一下<code>chunks</code>的字段含义。<br><code>chunks</code>有三个可选值，<code>all</code>、<code>initial</code>和<code>async</code></p>
<ul>
<li><code>async</code>：指定抽离动态引入的公共模块</li>
<li><code>initial</code>: 指定抽离非动态引入的公共模块</li>
<li><code>all</code>: 所有符合条件的公共模块都进行抽离<br>在引入模块时，通常都是非动态的引入，比如<code>import $ from &#39;jquery&#39;</code>;有时候也需要动态的引入一些模块，比如:<code>import (&#39;lodash&#39;)</code></li>
</ul>
</blockquote>
<h4 id="抽离第三方模块"><a href="#抽离第三方模块" class="headerlink" title="抽离第三方模块"></a>抽离第三方模块</h4><blockquote>
<p>上面讲解了抽离公用的模块，但没有区分是第三方包还是程序中开发的，我们可以把这两种情况分开，把第三方包重复使用的抽离到一起，自己开发的抽离到一起。</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  optimization: &#123;</span><br><span class="line">    splitChunks: &#123;</span><br><span class="line">      <span class="comment">// 分割代码块</span></span><br><span class="line">      cacheGroups: &#123;</span><br><span class="line">        <span class="comment">// 缓存组</span></span><br><span class="line">        common: &#123;</span><br><span class="line">          minSize: <span class="number">0</span>,</span><br><span class="line">          minChunks: <span class="number">2</span>,</span><br><span class="line">          chunks: <span class="string">"initial"</span>, <span class="comment">//只优化同步加载的模块</span></span><br><span class="line">          reuseExistingChunk: <span class="literal">true</span>,</span><br><span class="line">          priority: <span class="number">1</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        vendors: &#123;</span><br><span class="line">          test: <span class="regexp">/[\\/]node_modules[\\/]/</span>,</span><br><span class="line">          minSize: <span class="number">0</span>,</span><br><span class="line">          minChunks: <span class="number">2</span>,</span><br><span class="line">          chunks: <span class="string">"initial"</span>, <span class="comment">//只优化同步加载的模块</span></span><br><span class="line">          priority: <span class="number">2</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>其实就是再配置一个抽离方案，但要注意加上<code>priority</code>，因为程序是从上往下执行的，如果不加<code>priority</code>,下面的方案就不会被执行。<br>我们需要让<code>vendors</code>的权重比<code>common</code>的大，才能先把第三方的抽离，然后再抽离公共的。当然，也可以把<code>vendors</code>放到第一个。总之把条件范围小的权重大点，让先执行。</p>
<h3 id="懒加载"><a href="#懒加载" class="headerlink" title="懒加载"></a>懒加载</h3><p>懒加载说白就是使用 es6 草案的<code>import (&#39;jquery&#39;)</code>语法动态的加载 js。</p>
<h3 id="热更新"><a href="#热更新" class="headerlink" title="热更新"></a>热更新</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">	devServer: &#123;</span><br><span class="line">		hot: <span class="literal">true</span>,</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// ...</span></span><br><span class="line">	plugins: [</span><br><span class="line">		<span class="keyword">new</span> webpack.NamedModulesPlugin(), <span class="comment">// 打印更新的模块路径</span></span><br><span class="line">		<span class="keyword">new</span> webpack.HotModuleReplacementPlugin() <span class="comment">// 热更新插件</span></span><br><span class="line">	]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="tapable"><a href="#tapable" class="headerlink" title="tapable"></a>tapable</h3><p><code>Webpack</code>本质上是一种事件流的机制，它的工作流程就是将各个插件串联起来，而实现这一切的核心就是<code>Tapable</code>，<code>Tapable</code>有点类似于<code>nodejs</code>的<code>events</code>库，核心原理也是依赖<strong>订阅发布模式</strong>。</p>
<ul>
<li><p>SyncHook<br>这个比较简单，订阅的钩子一个一个都执行。</p>
</li>
<li><p>syncBailHook<br>任何一个钩子的返回值不是<code>undefined</code>，后面的钩子就不执行了。</p>
</li>
<li><p>SyncWaterfallHook<br>上一个钩子的返回结果传给下一个。</p>
</li>
<li><p>SyncLoopHook<br>钩子的返回值不是<code>undefined</code>，就一直执行。<br>上面三个都是同步的 Hook，下面介绍几个异步的 Hook。</p>
</li>
<li><p>AsyncParallelHook<br>异步并行的钩子，当所有的异步都执行完后，才执行最后的回调。</p>
<blockquote>
<p>这提供了判断“所有异步都结束”的方案，就是在每个钩子的回调函数必须接收一个回调的参数，这个回调的参数就是一个计数的 function，每个钩子结束后必须执行这个计数的 function。当计数和钩子的个数相等时，说明所有异步钩子执行完了。<br>现在使用`promise.all 实现起来就更方便了。</p>
</blockquote>
</li>
<li><p>AsyncSeriesHook<br>异步串行，当上一个异步执行完以后，再执行第二个异步钩子。<br>promise 版本实现原理</p>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">promise(...args)&#123;</span><br><span class="line">    <span class="keyword">let</span> [first,...others]=<span class="keyword">this</span>.tasks;</span><br><span class="line">    <span class="keyword">return</span> others.reduce(<span class="function">(<span class="params">p,n</span>)=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> p.then(<span class="function"><span class="params">()</span>=&gt;</span>n(...args))</span><br><span class="line">    &#125;,first(...args))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>就是使用数组的 reduce 方法和 promise 返回是仍是 promise 的特性。redux 的源码也是这个原理。</p>
<ul>
<li>AsyncSeriesWaterfallHook<br>异步串行瀑布，上一个异步执行完以后再执行下一个，但是上一个钩子的结果传给下一个，如果有错误，则停止后 面钩子的执行。</li>
</ul>
</div></article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">wenmu</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="http://blog.wangpengpeng.site/2020/01/09/10%E5%A4%A9%E5%BD%BB%E5%BA%95%E6%90%9E%E5%AE%9Awebpack4-0-%E7%AC%94%E8%AE%B0-1/">http://blog.wangpengpeng.site/2020/01/09/10%E5%A4%A9%E5%BD%BB%E5%BA%95%E6%90%9E%E5%AE%9Awebpack4-0-%E7%AC%94%E8%AE%B0-1/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank" rel="noopener">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="http://blog.wangpengpeng.site">温木的博客</a>！</span></div></div><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/webpack/">webpack</a></div><div class="post-qr-code"><div class="post-qr-code-item"><img class="post-qr-code__img" src="https://i.loli.net/2020/02/27/hOBzIxFDJMCrmtN.jpg"><div class="post-qr-code__desc">微信打赏</div></div></div><nav id="pagination"><div class="prev-post pull-left"><a href="/2020/01/09/10%E5%A4%A9%E5%BD%BB%E5%BA%95%E6%90%9E%E5%AE%9Awebpack4-0-%E7%AC%94%E8%AE%B0-2/"><i class="fa fa-chevron-left">  </i><span>10天彻底搞定webpack4.0-笔记(2)</span></a></div><div class="next-post pull-right"><a href="/2020/01/09/npm-install%E5%90%84%E7%A7%8D%E6%96%B9%E5%BC%8F%E7%9A%84%E4%BB%8B%E7%BB%8D/"><span>npm install各种方式的介绍</span><i class="fa fa-chevron-right"></i></a></div></nav><div id="vcomment"></div><script src="https://cdn1.lncld.net/static/js/3.0.4/av-min.js"></script><script src="https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js"></script><script>var notify = 'false' == true ? true : false;
var verify = 'false' == true ? true : false;
var GUEST_INFO = ['nick','mail','link'];
var guest_info = 'nick,mail,link'.split(',').filter(function(item){
  return GUEST_INFO.indexOf(item) > -1
});
guest_info = guest_info.length == 0 ? GUEST_INFO :guest_info;
window.valine = new Valine({
  el:'#vcomment',
  notify:notify,
  verify:verify,
  appId:'U1QqpeQNuBnRsfygHk1GQ30q-gzGzoHsz',
  appKey:'dunDQzEseDzgsKgw4qLQcog1',
  placeholder:'支持markdown！',
  avatar:'wavatar',
  guest_info:guest_info,
  pageSize:'20',
  lang: 'zh-cn'
})</script></div></div><footer><div class="layout" id="footer"><div class="copyright">&copy;2019 - 2020 By wenmu</div><div class="framework-info"><span>驱动 - </span><a href="http://hexo.io" target="_blank" rel="noopener"><span>Hexo</span></a><span class="footer-separator">|</span><span>主题 - </span><a href="https://github.com/Molunerfinn/hexo-theme-melody" target="_blank" rel="noopener"><span>Melody</span></a></div><div class="busuanzi"><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><span id="busuanzi_container_page_pv">该文访问量<span id="busuanzi_value_page_pv"></span><span></span></span></div></div></footer><i class="fa fa-arrow-up" id="go-up" aria-hidden="true"></i><script src="https://cdn.jsdelivr.net/npm/animejs@latest/anime.min.js"></script><script src="https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@latest/velocity.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-ui-pack@latest/velocity.ui.min.js"></script><script src="/js/utils.js?version=1.6.1"></script><script src="/js/fancybox.js?version=1.6.1"></script><script src="/js/sidebar.js?version=1.6.1"></script><script src="/js/copy.js?version=1.6.1"></script><script src="/js/fireworks.js?version=1.6.1"></script><script src="/js/transition.js?version=1.6.1"></script><script src="/js/scroll.js?version=1.6.1"></script><script src="/js/head.js?version=1.6.1"></script><script>if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
  $('#nav').addClass('is-mobile')
  $('footer').addClass('is-mobile')
}</script></body></html>